# 《go 语言实战》 读书笔记

# 第1章 关于 Go 语言的介绍

# 1.1 用 Go 解决现代编程难题

# 1.1.1 开发速度

Go 语言使用了更加智能的编译器,并简化了解决依赖的算法,最终提供了更快的编译速度。 编译 Go 程序时,编译器只会关注那些直接被引用的库,而不是像 Java、C 和 C++那样,要遍历 依赖链中所有依赖的库

# 1.1.2 并发

Go 语言对并发的支持是这门语言最重要的特性之一。goroutine 很像线程,但是它占用的 内存远少于线程,使用它需要的代码更少。通道(channel)是一种内置的数据结构,可以让 用户在不同的 goroutine 之间同步发送具有类型的消息。这让编程模型更倾向于在 goroutine 之间发送消息,而不是让多个 goroutine 争夺同一个数据的使用权。

# 1.1.3 Go 语言的类型系统

在 Go 语言中,一个类型由其他更微小的类型组合而成,避免了传统的基于 继承的模型。

优势:

  • 类型简单
  • Go 接口对一组行为建模

# 1.1.4 内存管理

想要弄懂 go 语言的代码回收机制,建议扩展阅读一下这篇文章,相信会有更大收获。Golang 垃圾回收剖析 | Legendtkl

# 1.2 你好,Go

package main //  Go 程序都组 织成包。
import "fmt" //  import 语句用于导入外部代码。标准 库中的 fmt 包用于格式化并输出数据
func main() {  // 像 C 语言一样,main 函 数是程序执行的入口。
    fmt.Println("Hello world!")
}

文章中介绍了一款在线运行 go 语言的工具 「Go Playground」,网址:http://play.golang.org,感兴趣的可以尝试一下。

# 1.3 小结

  • Go 语言是现代的、快速的,带有一个强大的标准库。
  • Go 语言内置对并发的支持。
  • Go 语言使用接口作为代码复用的基础模块。

# 第2章 快速开始一个Go程序

待补充

# 第3章 打包和工具链

# 3.1 包

什么是包?

  • 所有 Go 语言的程序都会组织成若干组文件,每组文件被称为一个包。这样每个包的代码都 可以作为很小的复用单元,被其他项目引用。

包的注意事项:

  • 所有的.go 文件,除了空行和注释,都应该在第一行声明自己所属的包
  • 每个包都在一个单独的目录里
  • 同一个目录下的所有.go 文件必须声明同一个包名

# 3.1.1 包名惯例

给包命名的惯例是使用包所在目录的名字

# 3.1.2 main 包

  • 所有用 Go 语言编译的可执行程序都必须有一个名叫 main 的包。
  • main()函数是程序的入口,所以,如果没有这个函数,程序就没有办法开始执行。
  • 程序编译时,会使用声明 main 包的代码所在的目录的目录名作为二进制可执行文件的文件名。

# 3.2 导入包

import (
  "fmt"
	"strings"		 // strings 包提供了很多关于字符串的操作,如查找、替换或 者变换。
)

# 3.2.1 远程导入

使用 go get 命令完成包的远程导入

# 3.2.2 命名导入

如果遇到导入的包名重名情况,可以使用命名导入的形式,命名导入是指,在 import 语句给出的包路径的左侧定义一个名字,将导入的包命名为新名字。

import (
   "fmt"
   myfmt "mylib/fmt"
)

注意:当你导入了一个不在代码里使用的包时,Go 编译器会编译失败,并输出一个错误。

如果你需要导入一个包,但是不需要引用这个包的标识符(有一种情况是,导入一个包,目的是执行包内的init 函数),则可以使用空白标识符_来重命名这个导入

import (
   _ "mylib/fmt"
)

概念补充:

空白标识符 下划线字符(_)在 Go 语言里称为空白标识符,有很多用法。这个标识符用来抛弃不 想继续使用的值,如给导入的包赋予一个空名字,或者忽略函数返回的你不感兴趣的值。

# 3.3 函数 init

  • 每个包可以包含任意多个 init 函数
  • init 函数都会在程序执行开始的时候被调用(main 函数之前调用)

作用:init 函数用在设置包、初始化变量 或者其他要在程序运行前优先完成的引导工作。

文中案例:

package postgres

import (
    "database/sql"
)
func init() { 
  sql.Register("postgres", new(PostgresDriver))
}
package main

import (
    "database/sql"
		_ "github.com/goinaction/code/chapter3/dbdriver/postgres"
)

func main() {
	sql.Open("postgres", "mydb") 
}

# 3.4 使用 Go 的工具

go build	// 构建包
go run main.go	//构建并执行

# 3.5 进一步介绍 Go 开发工具

go vet	// 检测代码的常见错误
go fmt 	// Go 代码格式化
go doc XXX(包名)	// 从命令行获取文档
godoc -http=:6060		// 开启一个文档服务器

# 3.6 与其他 Go 开发者合作

  • 包应该在代码库的根目录中
  • 包可以非常小
  • 对代码执行go fmt
  • 给代码写文档

# 3.7 依赖管理

不建议去学习书中提到的 godep、vender 和 gb等工具,建议去了解一下 go module

# 3.8 小结

  • 在 Go 语言中包是组织代码的基本单位。
  • 环境变量 GOPATH 决定了 Go 源代码在磁盘上被保存、编译和安装的位置。
  • 可以为每个工程设置不同的 GOPATH,以保持源代码和依赖的隔离。
  • go 工具是在命令行上工作的最好工具。
  • 开发人员可以使用go get来获取别人的包并将其安装到自己的GOPATH指定的目录。
  • 想要为别人创建包很简单,只要把源代码放到公用代码库,并遵守一些简单规则就可以了。
  • Go 语言在设计时将分享代码作为语言的核心特性和驱动力。
  • 推荐使用依赖管理工具来管理依赖。
  • 有很多社区开发的依赖管理工具,如 godep、vender 和 gb。

# 第4章 数组、4切片和映射(重要)

# 第 7 章 并发模式

# 7.1 runner

runner 介绍:runner 包用于展示如何使用通道来监视程序的执行时间,如果程序运行时间太长,也可以 用 runner 包来终止程序

设计特点:

  • 程序可以在分配的时间内完成工作,正常终止;
  • 程序没有及时完成工作,“自杀”;
  • 接收到操作系统发送的中断事件,程序立刻试图清理状态并停止工作。